package controller

import (
	"bytes"
	"encoding/csv"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"github.com/gookit/slog"
	"github.com/jinzhu/copier"
	"github.com/mariomac/gostream/stream"
	"github.com/minio/minio-go/v7"
	"go-process/config"
	"go-process/entity"
	"go-process/entity/req"
	"go-process/entity/vo"
	"go-process/result"
	"io"
	"net/http"
	"os"
	"strconv"
	"time"
)

type UserController struct {
}

func (user UserController) GetUserById(c *gin.Context) {
	slog.Info("获取用户信息接口调用")
	param := c.Param("id")
	e := entity.User{}
	id, err := strconv.Atoi(param)
	if err != nil {
		result.Error(c, result.BadRequestCode, "参数id的值必须为数字")
		return
	}
	byId, err := e.GetUserById(id)
	if err != nil {
		result.Error(c, result.BadRequestCode, "查询用户失败")
		return
	}
	result.Success(c, byId)

}
func (user UserController) GetUserList(c *gin.Context) {
	e := entity.User{}
	userPageReq := req.UserPageReq{}
	err := c.ShouldBind(&userPageReq)
	if err != nil {
		result.Error(c, result.BadRequestCode, err.Error())
		return
	}
	list, _ := e.GetUserList(userPageReq)
	total, _ := e.GetTotal(userPageReq)
	//将查询出来的数据拷贝成VO
	userVo := []vo.UserVO{}
	if err = copier.Copy(&userVo, list); err != nil {
		result.Error(c, result.BadRequestCode, "数据转换失败")
	}
	//将年龄加上岁
	finalUserVo := stream.OfSlice(userVo).Map(func(userVO vo.UserVO) vo.UserVO {
		userVO.Phone = "+86" + userVO.Phone
		return userVO
	}).ToSlice()
	result.PageSuccess(c, finalUserVo, total, userPageReq.PageNum, userPageReq.PageSize)

}
func (user UserController) CreateUser(c *gin.Context) {
	e := entity.User{}
	//参数绑定
	err := c.BindJSON(&e)
	if err != nil {
		result.Error(c, result.BadRequestCode, "参数绑定失败："+err.Error())
		return
	}
	//参数校验
	if err := validator.New().Struct(e); err != nil {
		result.Error(c, result.BadRequestCode, "参数校验失败："+err.Error())
		return
	}
	//其他逻辑(参数赋值等)
	e.CreateTime = time.Now()
	e.UpdateTime = time.Now()
	//插入数据
	_, err = e.Insert()
	if err != nil {
		result.Error(c, result.BadRequestCode, "插入数据错误"+err.Error())
		return
	}
	result.Success(c, e)
}
func (user UserController) UpdateUser(c *gin.Context) {
	e := entity.User{}
	err := c.ShouldBind(&e)
	e.UpdateTime = time.Now()
	e.CreateTime = time.Now()
	update, err := e.Update()
	if err != nil {
		result.Error(c, result.BadRequestCode, "更新失败")
		return
	}
	result.Success(c, update)
}
func (user UserController) DeleteUser(c *gin.Context) {
	id := c.Param("id")
	e := entity.User{}
	userId, _ := strconv.Atoi(id)
	_, err := e.Delete(userId)
	if err != nil {
		result.Error(c, result.BadRequestCode, "删除失败")
		return
	}
	result.Success(c, "删除成功")
}

// 上传单个文件，并将文件保存到临时目录
func (user UserController) FileUpload(context *gin.Context) {
	file, err := context.FormFile("file")
	if err != nil {
		result.Error(context, result.BadRequestCode, "上传失败")
		return
	}
	fmt.Println("文件的地址：", file.Filename)
	//将文件上传到MinIO
	open, _ := file.Open()
	var reader io.Reader = open
	info, err := config.MinIoClient.PutObject(context.Request.Context(), "wyn", file.Filename, reader, file.Size, minio.PutObjectOptions{ContentType: "application/octet-stream"})
	if err != nil {
		result.Error(context, result.BadRequestCode, "上传失败")
		return
	} else {
		slog.Info("上传成功：", info)
	}
	address := "temp/" + file.Filename
	if err := context.SaveUploadedFile(file, address); err != nil {
		result.Error(context, result.BadRequestCode, "上传失败")
		return
	}
	result.Success(context, "上传成功")
}

// 上传多个文件
func (user UserController) FileUploadMultiple(context *gin.Context) {
	files, err := context.MultipartForm()
	if err != nil {
		result.Error(context, result.BadRequestCode, "上传失败")
		return
	}
	fileArray := files.File["file"]
	for item := range fileArray {
		file := fileArray[item]
		pathPrefix := "temp/"
		if err := context.SaveUploadedFile(file, pathPrefix+file.Filename); err != nil {
			result.Error(context, result.BadRequestCode, "上传失败")
			return
		}
	}
	result.Success(context, "上传成功")
}

//文件直接下载下载
//func (user UserController) FileDownload(context *gin.Context) {
//	fileName := context.Param("name")
//	if _, err := os.Stat("temp/" + fileName); os.IsNotExist(err) {
//		result.Error(context, result.BadRequestCode, "文件不存在")
//	}
//	context.Header("Content-Disposition", "attachment; filename="+fileName) //设置下载的文件名
//	context.Header("Content-Transfer-Encoding", "binary")
//	context.Header("Content-Type", "application/octet-stream")
//	context.File("temp/" + fileName)
//
//}

// 文件流式下载
func (user UserController) FileDownload(context *gin.Context) {
	fileName := context.Param("name")
	if _, err := os.Stat("temp/" + fileName); os.IsNotExist(err) {
		result.Error(context, result.BadRequestCode, "文件不存在")
	}
	context.Header("Content-Disposition", "attachment; filename="+fileName) //设置下载的文件名
	context.Header("Content-Transfer-Encoding", "binary")
	context.Header("Content-Type", "application/octet-stream")
	//下载MinIO上的文件，然后写入到响应流中（文件名要完全相同，后缀也要一样）
	object, err2 := config.MinIoClient.GetObject(context.Request.Context(), "wyn", fileName, minio.GetObjectOptions{})
	if err2 != nil {
		result.Error(context, result.BadRequestCode, "文件不存在")
	}

	//open, err := os.Open("temp/" + fileName) //将文件加载进内存
	//if err != nil {
	//	result.Error(context, result.BadRequestCode, "文件不存在")
	//}
	io.Copy(context.Writer, object) //将文件内容写入到响应流中

}

// 动态生成文件并下载
func (user UserController) FileDownloadCSV(context *gin.Context) {
	var buffer bytes.Buffer
	writer := csv.NewWriter(&buffer)
	writer.Write([]string{"id", "name", "phone"})
	writer.Write([]string{"1", "张三", "13888888888"})
	writer.Write([]string{"2", "张三", "13888888888"})
	writer.Write([]string{"3", "张三", "13888888888"})
	writer.Flush()
	context.Header("Content-Disposition", "attachment; filename=users.csv")
	context.Header("Content-Transfer-Encoding", "binary")
	context.Header("Content-Type", "application/octet-stream")
	context.Data(http.StatusOK, "text/csv", buffer.Bytes())

}
